<template>
    <el-dialog v-model="dialogVisible" title="上传文件" width="600px">
        <div class="upload-container">
            <el-upload ref="uploadRef" class="upload-dragger" drag action="#" :auto-upload="false"
                :on-change="handleChange" :before-upload="beforeUpload" :on-exceed="onExceed" :limit="limit"
                :show-file-list="false">
                <el-icon class="el-icon--upload"><upload-filled /></el-icon>
                <div class="el-upload__text">
                    将文件拖到此处，或<em>点击上传</em>
                </div>
            </el-upload>

            <div class="file-list" v-if="fileList.length > 0">
                <div class="file-item" v-for="(file, index) in fileList" :key="index">
                    <div class="file-info">
                        <el-icon>
                            <document />
                        </el-icon>
                        <span class="file-name" :title="file.name">{{ file.name }}</span>
                        <span class="file-size">{{ formatFileSize(file.size) }}</span>
                    </div>
                    <div class="file-status">
                        <template v-if="file.status === 'ready'">
                            <el-tag size="small" type="info">待上传</el-tag>
                        </template>
                        <template v-else-if="file.status === 'uploading'">
                            <div class="upload-progress">
                                <el-progress :percentage="file.progress || 0"
                                    :status="file.progress === 100 ? 'success' : ''" :stroke-width="4"
                                    :show-text="true" />
                            </div>
                        </template>
                        <template v-else-if="file.status === 'success'">
                            <el-tag size="small" type="success">已上传</el-tag>
                        </template>
                        <template v-else-if="file.status === 'error'">
                            <el-tooltip :content="file.errorMessage || '上传失败'" placement="top">
                                <el-tag size="small" type="danger">上传失败</el-tag>
                            </el-tooltip>
                        </template>
                    </div>
                    <div class="file-actions">
                        <el-button v-if="file.status === 'error'" type="primary" link @click="retryUpload(file)">
                            重试
                        </el-button>
                        <el-button type="danger" link @click="removeFile(index)">
                            删除
                        </el-button>
                    </div>
                </div>
            </div>

            <div class="upload-tip">
                <p>支持上传任意类型文件，单个文件大小不超过 {{ formatFileSize(maxSize) }}</p>
            </div>
        </div>

        <template #footer>
            <div class="dialog-footer">
                <el-button @click="dialogVisible = false">取消</el-button>
                <el-button type="primary" @click="handleUpload" :loading="uploading" :disabled="fileList.length === 0">
                    {{ uploading ? '上传中...' : '开始上传' }}
                </el-button>
            </div>
        </template>
    </el-dialog>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { UploadFilled, Document } from '@element-plus/icons-vue'
import type { UploadInstance, UploadProps, UploadUserFile, UploadFile } from 'element-plus'
import { FILE_TYPES, getFileType, formatFileSize } from '@/config/fileTypes'
import { ossGetInfo, UploadFileInfo } from '@/apis/file'
import type { OssResponse, UploadInfoResponse } from '@/apis/file'
import OSS from "ali-oss";
import dayjs from "dayjs";

interface ExtendedUploadFile extends Omit<UploadFile, 'status'> {
    status: 'ready' | 'uploading' | 'success' | 'error'
    progress?: number
    errorMessage?: string
}

const props = withDefaults(defineProps<{
    modelValue: boolean
    limit?: number
    accept?: string
}>(), {
    limit: 10,
    accept: undefined
})

const emit = defineEmits<{
    (e: 'update:modelValue', value: boolean): void
    (e: 'success'): void
    (e: 'error', error: any): void
}>()

const uploadRef = ref<UploadInstance>()
const dialogVisible = ref(props.modelValue)
const fileList = ref<ExtendedUploadFile[]>([])

// 上传状态
const uploading = ref(false)
const uploadPercent = ref(0)
const uploadStatus = ref<'success' | 'exception'>('success')
const uploadStatusText = ref('')

// OSS配置
const ossConfig = ref({
    partSize: 1024 * 1024, // 每个分片大小(byte)
    parallel: 3, // 同时上传的分片数
    path: dayjs().format("YYYYMMDD"),
    bucket: '',
    region: '',
    endpoint: ''
})
const maxSize = ref<number>(0)

// OSS客户端
let ossClient: OSS | null = null

// 始化OSS客户端
const initOssClient = async () => {
    try {
        const res = await ossGetInfo()
        const ossInfo = res as OssResponse
        if (ossInfo) {
            ossClient = new OSS({
                accessKeyId: ossInfo.credentials.AccessKeyId,
                accessKeySecret: ossInfo.credentials.AccessKeySecret,
                region: ossInfo.address,
                stsToken: ossInfo.credentials.securityToken,
                bucket: ossInfo.bucket,
                endpoint: ossInfo.point,
            });
        }
    } catch (error) {
        console.error('获取OSS配置失败:', error)
        ElMessage.error('获取上传配置失败')
    }
}

watch(() => props.modelValue, (val) => {
    dialogVisible.value = val
    if (val) {
       
        resetUpload()
    }
})

watch(dialogVisible, (val) => {
    emit('update:modelValue', val)
})

// 重置上传状态
const resetUpload = () => {
    uploading.value = false
    uploadPercent.value = 0
    uploadStatus.value = 'success'
    uploadStatusText.value = ''
    fileList.value = []
}

// 文件选择改变
const handleChange: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
    const newFile = uploadFile as ExtendedUploadFile
    newFile.status = 'ready'
    fileList.value = uploadFiles as ExtendedUploadFile[]
}

// 上传前验证
const beforeUpload: UploadProps['beforeUpload'] = (file) => {
    // 获取文件类型
    const suffix = file.name.substring(file.name.lastIndexOf('.') + 1)
    const { type, config } = getFileType(suffix)

    // 验证文件大小
    if (file.size > config.maxSize) {
        ElMessage.error(`${config.label}文件大小不能超过${formatFileSize(config.maxSize)}`)
        return false
    }
    maxSize.value = config.maxSize

    // 验证文件类型
    if (type === 'other') {
        ElMessage.error('不支持的文件类型')
        return false
    }

    return true
}

// 移除文件
const removeFile = (index: number) => {
    fileList.value.splice(index, 1)
}

// 重试上传
const retryUpload = async (file: ExtendedUploadFile) => {
    file.status = 'ready'
    await uploadFile(file)
}

// 上传单个文件
const uploadFile = async (file: ExtendedUploadFile) => {
   
    if (!file.raw || !ossClient) return false

    try {
        file.status = 'uploading'
        file.progress = 0
        const ossPath = `${ossConfig.value.path}/${file.name}`
        let result;

        // 判断文件大小，大于1MB使用分片上传
        if (file.size > 1024 * 1024) {
            result = await ossClient.multipartUpload(ossPath, file.raw, {
                parallel: ossConfig.value.parallel,
                partSize: ossConfig.value.partSize,
                progress: (p: number) => {
                    file.progress = Math.floor(p * 100)
                }
            })
        } else {
            // 小文件使用普通上传
            result = await ossClient.put(ossPath, file.raw)
            file.progress = 100
        }

        // 上传成功后保存文件信息
        const fileInfo: UploadInfoResponse = {
            name: file.name,
            size: file.size,
            suffix: file.name.substring(file.name.lastIndexOf('.') + 1),
            path:  result.res.requestUrls[0],
            userId: localStorage.getItem('userId') || '',
            groupName: 'default',
            uUid: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
        }

        await UploadFileInfo(fileInfo)

        file.status = 'success'
        file.progress = 100
        return true
    } catch (error) {
        console.error('上传失败:', error)
        file.status = 'error'
        file.errorMessage = '上传失败'
        return false
    }
}

// 处理上传
const handleUpload = async () => {
    await initOssClient()
    if (!ossClient) {
        ElMessage.error('OSS客户端未初始化')
        return
    }

    if (fileList.value.length === 0) {
        ElMessage.warning('请选择要上传的文件')
        return
    }

    uploading.value = true
    uploadStatusText.value = '准备上传...'
    let successCount = 0

    try {
        for (let i = 0; i < fileList.value.length; i++) {
            const file = fileList.value[i]
            if (file.status === 'success') {
                successCount++
                continue
            }

            uploadStatusText.value = `正在上传 ${file.name}...`
            const success = await uploadFile(file)
            if (success) successCount++

            // 更新总进度
            uploadPercent.value = Math.round((successCount / fileList.value.length) * 100)
        }

        if (successCount === fileList.value.length) {
            uploadStatus.value = 'success'
            uploadStatusText.value = '上传成功'
            ElMessage.success('上传成功')
            emit('success')

            setTimeout(() => {
                dialogVisible.value = false
            }, 1000)
        } else {
            uploadStatus.value = 'exception'
            uploadStatusText.value = '部分文件上传失败'
            ElMessage.warning('部分文件上传失败，请重试')
        }
    } catch (error) {
        uploadStatus.value = 'exception'
        uploadStatusText.value = '上传失败'
        console.error('上传失败:', error)
        ElMessage.error('上传失败')
        emit('error', error)
    } finally {
        uploading.value = false
    }
}

const onExceed = (files: File[]) => {
    ElMessage.warning(`当前限制选择 ${props.limit} 个文件，本次选择了 ${files.length} 个文件`)
}

// 暴露方法
defineExpose({
    uploadRef
})
</script>

<style scoped lang="scss">
.upload-container {
    .upload-dragger {
        width: 100%;
    }

    .file-list {
        margin: 20px 0;
        max-height: 300px;
        overflow-y: auto;

        .file-item {
            display: flex;
            align-items: center;
            padding: 8px;
            border-radius: 4px;
            transition: background-color 0.3s;

            &:hover {
                background-color: var(--el-fill-color-light);
            }

            .file-info {
                flex: 1;
                display: flex;
                align-items: center;
                gap: 8px;

                .file-name {
                    flex: 1;
                    @include text-ellipsis;
                }

                .file-size {
                    color: var(--el-text-color-secondary);
                    font-size: 12px;
                }
            }

            .file-status {
                margin: 0 16px;
                min-width: 100px;

                .upload-progress {
                    width: 100px;
                }
            }

            .file-actions {
                display: flex;
                gap: 8px;
            }
        }
    }
}
</style>